package api

import (
	"TaskAssignmentSystem/internal/admin/dao"
	"TaskAssignmentSystem/internal/admin/services"
	"TaskAssignmentSystem/internal/pkg/code"
	"TaskAssignmentSystem/internal/pkg/middleware/handler"
	"TaskAssignmentSystem/internal/pkg/middleware/mysqlhandler"
	"TaskAssignmentSystem/pkg/oss"
	"TaskAssignmentSystem/pkg/utils"
	"errors"
	"fmt"
	"github.com/go-the-way/exl"
	"github.com/kataras/iris/v12"
	"github.com/tealeg/xlsx"
	"io/ioutil"
	"os"
	"strings"
	"time"
)

// excel导入商品
func SystemProductImportsHandler(ctx iris.Context) {
	_, handle, err := ctx.FormFile("file")
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	file, _ := handle.Open()
	defer file.Close()
	fileByte, err := ioutil.ReadAll(file) //获取上传文件字节流
	if err != nil {
		fmt.Println(err)
	}
	xlFile, err := xlsx.OpenBinary(fileByte)
	if err != nil {
		fmt.Printf("open failed: %s\n", err)
	}
	titles := []string{"商品序号", "商品ID(必填)", "商品名字（必填）", "商品类型（1表示现金，2表示商品）（必填）", "商品单价（芝草）（必填）", "上架数量，不填表示无限，填了有数量限制（选填）", "上架/下架（必填）", "详情地址（必填）", "图片地址（必填）"}
	var productDao dao.Common[dao.SystemProduct]
	var res ImportsResponse
	for _, sheet := range xlFile.Sheets {

		for i, row := range sheet.Rows {
			var errListLength = len(res.ErrList)
			//判断excel格式对不对
			if i == 0 {
				for j, cell := range row.Cells {
					if strings.TrimSpace(cell.String()) != titles[j] {
						ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: fmt.Sprintf("文件表头格式不对,表头%s的名称有误", cell.String())})
						return
					}
				}
			}

			//从第三行开始
			if i >= 2 {
				res.TotalRows += 1
				var rowsList []string
				var obj dao.SystemProduct
				var row_data string
				for j, cell := range row.Cells {
					text := strings.TrimSpace(cell.String())
					row_data += text
					if text == "" && j < len(titles) {
						//商品数量可为空
						if j == 5 {
							text = "-1"
						} else {
							res.ErrList = append(res.ErrList, code.ImportError{
								Number: i + 1,
								Cell:   j + 1,
								Reason: fmt.Sprintf("第%d行字段%s的值不能为空", i+1, titles[j]),
							})
						}
					}
					rowsList = append(rowsList, text)
				}
				if strings.TrimSpace(row_data) == "" {
					res.TotalRows -= 1
					break
				}
				if len(rowsList) < len(titles) {
					for k := len(rowsList); k < len(titles); k++ {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   k + 1,
							Reason: fmt.Sprintf("第%d行字段%s的值不能为空", i+1, titles[k]),
						})
					}
					res.FailRows += 1
					continue
				}

				obj.ProductId = rowsList[1]
				obj.ProductName = rowsList[2]
				if pt, err := utils.StringToUint(rowsList[3]); err != nil {
					res.ErrList = append(res.ErrList, code.ImportError{
						Number: i + 1,
						Cell:   2 + 1,
						Reason: fmt.Sprintf("第%d字段%s的数据格式不对", i+1, titles[6]),
					})
				} else {
					obj.ProductType = pt
				}
				if pp, err := utils.StringToFloat64(rowsList[4]); err != nil {
					res.ErrList = append(res.ErrList, code.ImportError{
						Number: i + 1,
						Cell:   3 + 1,
						Reason: fmt.Sprintf("第%d字段%s的数据格式不对", i+1, titles[6]),
					})
				} else {
					obj.ProductPrice = pp
				}
				if pn, err := utils.StringToInt(rowsList[5]); err != nil {
					res.ErrList = append(res.ErrList, code.ImportError{
						Number: i + 1,
						Cell:   4 + 1,
						Reason: fmt.Sprintf("第%d字段%s的数据格式不对", i+1, titles[6]),
					})
				} else {
					obj.ProductNumber = pn
				}
				if status, err := utils.StringToUint(rowsList[6]); err != nil {
					res.ErrList = append(res.ErrList, code.ImportError{
						Number: i + 1,
						Cell:   5 + 1,
						Reason: fmt.Sprintf("第%d字段%s的数据格式不对", i+1, titles[6]),
					})
				} else {
					obj.Status = status
				}
				obj.ProductDetailPath = rowsList[7]
				obj.ProductPicturePath = rowsList[8]

				if len(res.ErrList) > errListLength {
					if len(res.ErrList)-errListLength >= len(titles) {
						break
					} else {
						res.FailRows += 1
						continue
					}
				}
				if err := productDao.CreateOrUpdate(obj, "ProductId").Error; err != nil {

					switch mysqlhandler.MysqlErrCode(err) {
					case mysqlhandler.ErrDuplicateEntryCode:
						res.ErrList = append(res.ErrList, code.ImportError{Number: i + 1, Reason: "该条数据已经存在,请检查商品ID是否已经存在"})
					default:
						res.ErrList = append(res.ErrList, code.ImportError{Number: i + 1, Reason: err.Error()})
					}
					res.FailRows += 1
					continue
				}
			}
		}
	}
	res.SuccessRows = res.TotalRows - res.FailRows
	ctx.JSON(utils.Response{
		Code:    200,
		Message: "ok",
		Data:    res,
	})
	return
}

type SystemProductImportsNew struct {
	ProductId          string  `excel:"商品ID(必填)"`                //商品ID
	ProductName        string  `excel:"商品名字（必填）"`                //商品名称
	ProductType        uint    `excel:"商品类型（1表示现金，2表示商品）（必填）"`   //商品类型，1：现金，2：商品
	ProductPrice       float64 `excel:"商品单价（芝草）（必填）"`            //商品单价（芝草）
	ProductNumber      string  `excel:"上架数量，不填表示无限，填了有数量限制（选填）"` //上架数量，不填(-1)表示无限，填了有数量限制，0表示已兑换完
	ProductDetailPath  string  `excel:"详情地址（必填）"`                //商品详情地址
	ProductPicturePath string  `excel:"图片地址（必填）"`                //商品图片地址
	Status             uint    `excel:"上架/下架（必填）"`               //状态，1：上架，0：下架
	Sort               uint    `excel:"商品序号"`                    //排序（选填）
}

func (*SystemProductImportsNew) Configure(rc *exl.ReadConfig) {}
func SystemProductImportsNewHandler(ctx iris.Context) {
	_, handle, err := ctx.FormFile("file")
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	file, _ := handle.Open()
	defer file.Close()
	if models, err := exl.Read[*SystemProductImportsNew](file); err != nil {
		fmt.Println("read excel err:" + err.Error())
		ctx.JSON(utils.ResponseServerError(errors.New("excel读取错误")))
		return
	} else {
		fmt.Printf("read excel num: %d\n", len(models))
		var productObjs []*dao.SystemProduct
		index := 0
		for i, model := range models {
			//从第二行开始读取
			if i == 0 {
				continue
			}
			var productObj dao.SystemProduct
			productObj.ProductId = model.ProductId
			productObj.ProductName = model.ProductName
			productObj.ProductType = model.ProductType
			productObj.ProductPrice = model.ProductPrice
			if utils.StringIsEmpty(model.ProductNumber) {
				productObj.ProductNumber = -1
			} else {
				productObj.ProductNumber, _ = utils.StringToInt(model.ProductNumber)
			}
			productObj.ProductDetailPath = model.ProductDetailPath
			productObj.ProductPicturePath = model.ProductPicturePath
			productObj.Sort = model.Sort
			productObjs = append(productObjs, &productObj)
			index++
		}
		var productServe services.SystemProductService
		if err := productServe.BatchImportProducts(productObjs); err != nil {
			ctx.JSON(utils.ResponseServerError(err))
			return
		}
		ctx.JSON(utils.ResponseOK())
		return
	}
}

type ProductQueryRequest struct {
	Page            int64  `json:"page" validate:"required"`
	PageSize        int64  `json:"page_size" validate:"required"`
	ProductId       string `json:"product_id"`
	ProductName     string `json:"product_name"`
	ProductType     string `json:"product_type"`
	Status          string `json:"status"`
	ProductPriceMin string `json:"product_price_min"`
	ProductPriceMax string `json:"product_price_max"`
}

func ProductListHandler(ctx iris.Context) {
	var RequestParams ProductQueryRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}

	var serve services.SystemProductService
	var param = make(map[string]string)
	if utils.StringIsNotEmpty(RequestParams.ProductId) {
		param["product_id"] = RequestParams.ProductId
	}
	if utils.StringIsNotEmpty(RequestParams.ProductName) {
		param["product_name"] = RequestParams.ProductName
	}
	if utils.StringIsNotEmpty(RequestParams.ProductType) {
		param["product_type"] = RequestParams.ProductType
	}
	if utils.StringIsNotEmpty(RequestParams.Status) {
		param["status"] = RequestParams.Status
	}
	if utils.StringIsNotEmpty(RequestParams.ProductPriceMin) {
		param["product_price_min"] = RequestParams.ProductPriceMin
	}
	if utils.StringIsNotEmpty(RequestParams.ProductPriceMax) {
		param["product_price_max"] = RequestParams.ProductPriceMax
	}
	if total, list, err := serve.ProductFindAll(RequestParams.Page, RequestParams.PageSize, param); err != nil {
		ctx.JSON(utils.ResponseServerError(err))
		return
	} else {
		ctx.JSON(utils.ResponseData(iris.Map{"count": total, "list": list}))
		return
	}
}

func ProductAppListHandler(ctx iris.Context) {
	var RequestParams ProductQueryRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}

	var serve services.SystemProductService
	var param = make(map[string]string)
	param["status"] = utils.IntToString(services.ProductOnline)
	if total, list, err := serve.ProductFindAll(RequestParams.Page, RequestParams.PageSize, param); err != nil {
		ctx.JSON(utils.ResponseServerError(err))
		return
	} else {
		ctx.JSON(utils.ResponseData(iris.Map{"count": total, "list": list}))
		return
	}
}

func ProductUpdatePicturePathHandler(ctx iris.Context) {
	productId := ctx.PostValue("product_id")
	var serve services.SystemProductService
	if _, err := serve.ProductFindByProductId(productId); err != nil {
		ctx.JSON(utils.ResponseServerError(errors.New("该商品不存在")))
		return
	}

	_, handle, err := utils.FormFile(ctx, "file")
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	file, err := handle.Open()
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}

	//获取当前时间的月份
	currentMonth := time.Now().In(utils.LocationZone).Format("2006-01")

	//关闭打开文件
	defer file.Close()
	fileByte, err := ioutil.ReadAll(file) //获取上传文件字节流
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	var claims services.CustomClaims
	if err := claims.ParseClaims(ctx); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}

	var ossClient oss.BucketClient
	if handle.Filename == "image.jpg" {
		handle.Filename = fmt.Sprintf("%d.jpeg", time.Now().Unix())
	}

	fileName := fmt.Sprintf("task-assign/product/%s/%s", currentMonth, handle.Filename)
	if err := ossClient.UpBytes(fileByte, fileName); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	} else {
		webPath := fmt.Sprintf("%s/%s", utils.ServerConf.AliOssConf.CallBackHost, fileName)
		if err := serve.ProductUpdatePicturePath(productId, webPath); err != nil {
			ctx.JSON(utils.ResponseServerError(err))
			return
		} else {
			ctx.JSON(utils.ResponseData(webPath))
			return
		}
	}
}

type ProductUpdateRequest struct {
	UpType     string `json:"up_type" validate:"required"`
	ProductId  string `json:"product_id"`
	Status     uint   `json:"status"`
	ProductIds string `json:"product_ids"`
}

func ProductUpdateHandler(ctx iris.Context) {
	var RequestParams ProductUpdateRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}

	var err error
	var serve services.SystemProductService
	if RequestParams.UpType != "4" {
		if _, err := serve.ProductFindByProductId(RequestParams.ProductId); err != nil {
			ctx.JSON(utils.ResponseServerError(errors.New("该商品不存在")))
			return
		}
	}

	if RequestParams.UpType == "1" {
		//上架
		err = serve.ProductUpdateStatus(RequestParams.ProductId, services.ProductOnline)
	} else if RequestParams.UpType == "2" {
		//下架
		err = serve.ProductUpdateStatus(RequestParams.ProductId, services.ProductOffline)
	} else if RequestParams.UpType == "3" {
		//删除
		err = serve.ProductDel(RequestParams.ProductId)
	} else if RequestParams.UpType == "4" {
		//批量删除
		productIds := strings.Split(RequestParams.ProductIds, ",")
		err = serve.ProductBatchDel(productIds)
	} else {
		err = errors.New("修改类型错误")
	}
	if err != nil {
		ctx.JSON(utils.ResponseServerError(err))
		return
	} else {
		ctx.JSON(utils.ResponseOK())
		return
	}
}

type BatchDeleteProductRequest struct {
	Ids []uint `json:"ids" validate:"required"`
}

func BatchDeleteProductHandler(ctx iris.Context) {
	var RequestParams BatchDeleteProductRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}

	var productServe dao.Common[dao.SystemProduct]
	//传了ID删除符合的ID
	if len(RequestParams.Ids) > 0 {
		if err := productServe.RemoveUnscopedWhere(map[string]interface{}{"id": RequestParams.Ids}).Error; err != nil {
			ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
			return
		} else {
			ctx.JSON(utils.ResponseOK())
			return
		}
	} else {
		//没传ID删所有可以删除的
		var canDelIds []uint
		if list, err := productServe.FindAll(map[string]interface{}{}); err == nil {
			for _, model := range list {
				canDelIds = append(canDelIds, model.Id)
			}
			if err := productServe.RemoveUnscopedWhere(map[string]interface{}{"id": canDelIds}).Error; err != nil {
				ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
				return
			} else {
				ctx.JSON(utils.ResponseOK())
				return
			}
		}
	}
	ctx.JSON(utils.ResponseServerError)
	return
}

type SystemProductExports struct {
	ProductNo          uint    `excel:"商品序号"`                //商品序号
	ProductId          string  `excel:"商品ID"`                //商品ID
	ProductName        string  `excel:"商品名字"`                //商品名称
	ProductType        uint    `excel:"商品类型"`                //商品类型，1：现金，2：商品
	ProductPrice       float64 `excel:"商品单价（芝草）"`            //商品单价（芝草）
	ProductNumber      string  `excel:"上架数量，不填表示无限，填了有数量限制"` //上架数量，不填(-1)表示无限，填了有数量限制，0表示已兑换完
	ProductDetailPath  string  `excel:"详情地址"`                //商品详情地址
	ProductPicturePath string  `excel:"商品图片地址"`              //商品图片地址
	Status             string  `excel:"上架/下架"`               //状态，1：上架，0：下架
}

type SystemProductExportsRequest struct {
	Ids []int `json:"ids"`
}

func (*SystemProductExports) Configure(rc *exl.WriteConfig) {}
func SystemProductExportsHandler(ctx iris.Context) {
	var RequestParams SystemProductExportsRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}

	var serve dao.Common[dao.SystemProduct]
	queryMap := map[string]interface{}{}
	if len(RequestParams.Ids) > 0 {
		queryMap["id"] = RequestParams.Ids
	}
	ExportData, err := serve.FindAllOrderBy(queryMap, "sort")
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	var products []*SystemProductExports
	for _, model := range ExportData {
		var productObj SystemProductExports
		productObj.ProductId = model.ProductId
		productObj.ProductName = model.ProductName
		productObj.ProductType = model.ProductType
		productObj.ProductPrice = model.ProductPrice
		if model.ProductNumber == -1 {
			productObj.ProductNumber = ""
		} else {
			productObj.ProductNumber = string(model.ProductNumber)
		}
		productObj.ProductDetailPath = model.ProductDetailPath
		productObj.ProductPicturePath = model.ProductPicturePath
		productObj.ProductNo = model.Sort
		if model.Status == 0 {
			productObj.Status = "下架"
		} else if model.Status == 1 {
			productObj.Status = "上架"
		}
		products = append(products, &productObj)
	}

	unix := time.Now().UnixNano()
	if err := exl.Write(fmt.Sprintf("./export/export_product_records_%d.xlsx", unix), products); err != nil {
		fmt.Println("write excel err:" + err.Error())
		return
	}
	tempFilename := fmt.Sprintf("./export/export_product_records_%d.xlsx", unix)
	//删除本地临时文件
	defer os.Remove(tempFilename)
	bucketClient := oss.BucketClient{}
	readFile, _ := ioutil.ReadFile(fmt.Sprintf("./export/export_product_records_%d.xlsx", unix))
	bucketClient.UpBytes(readFile, fmt.Sprintf("task-assign/export/export_product_records_%d.xlsx", unix))
	ctx.JSON(utils.Response{Code: iris.StatusOK, Message: iris.StatusText(iris.StatusOK), Data: fmt.Sprintf("%s/task-assign/export/export_product_records_%d.xlsx", utils.ServerConf.AliOssConf.CallBackHost, unix)})
	return
}

type SystemProductImportsDel struct {
	ProductId string `excel:"商品ID(必填)"` //商品ID
}

func (*SystemProductImportsDel) Configure(rc *exl.ReadConfig) {}
func SystemProductImportsDelHandler(ctx iris.Context) {
	_, handle, err := ctx.FormFile("file")
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	file, _ := handle.Open()
	defer file.Close()
	if models, err := exl.Read[*SystemProductImportsDel](file); err != nil {
		fmt.Println("read excel err:" + err.Error())
		ctx.JSON(utils.ResponseServerError(errors.New("excel读取错误")))
		return
	} else {
		fmt.Printf("read excel num: %d\n", len(models))
		var productObjs []*dao.SystemProduct
		index := 0
		for i, model := range models {
			//从第二行开始读取
			if i == 0 {
				continue
			}
			var productObj dao.SystemProduct
			productObj.ProductId = model.ProductId
			productObjs = append(productObjs, &productObj)
			index++
		}
		var productServe services.SystemProductService
		if err := productServe.BatchDelProducts(productObjs); err != nil {
			ctx.JSON(utils.ResponseServerError(err))
			return
		}
		ctx.JSON(utils.ResponseOK())
		return
	}
}
